package com.operation.page;

import com.operation.GlobalArgument;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.LinkedList;

/**
 * 页表设计
 */
@Data
@NoArgsConstructor
public class PageList {

    //表项设计
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    static class Item{
        private int pageNumber;//页号
        private int memoryNumber;//物理块号
        private int state;//状态，是否在内存中
        private int visit;//访问次数
        private int modified;//修改位
        private long address;//外存地址
    }
    //默认值设定
    String name;//名称
    private LinkedList<Item>list;//页表
    private int length;//长度
    private int index;//初始页表分配表项时下标


    public PageList(String name,int length){
        this.name = name;
        this.length = length;
        this.list = new LinkedList<Item>();
        this.index = 0;
    }

    /**
     * 检查页号是否越界
     * @param pageNumber 页号
     * @return 越界与否
     */
    public boolean checkPageNumber(int pageNumber){

        if(pageNumber<0||pageNumber>GlobalArgument.JobEndAddress/GlobalArgument.pageSize){
            throw new IllegalArgumentException("页号越界");
        }
        return true;
    }
    /**
     * 检查页号是否命中
     * @param pageNumber 页号
     * @return 内存块号
     */
    public int isHit(int pageNumber){

        this.checkPageNumber(pageNumber);

        if(this.list.size()==0)return -1;
        for (Item item : this.list) {
            //页号相等且在内存当中
            if(item.getPageNumber()==pageNumber&&item.getState()==1){
                item.visit++;//访问次数增加
                return item.memoryNumber;
            }
        }
        return -1;
    }

    /**
     * 置换相应的页面
     * @param source 待置换页面
     * @param current 当前页面
     * @return 置换成功与否
     */
    public boolean replacePage(int source,int current,int modified,long address){

        this.checkPageNumber(current);
        if(source==-1&&this.list.size()<length){
            //表示不需要置换，仅仅是新加表项

            this.addItem(current,this.index,0,0);
            this.index++;
            return true;
        }
        for(int i=0;i<this.list.size(); i++){
            if(this.list.get(i).pageNumber==source){
                //置换页面
                int memoryNumber = this.list.get(i).memoryNumber;
                this.list.remove(i);
                this.addItem(current,memoryNumber,modified,address);
                return true;
            }
        }
        return false;
    }

    /**
     * 置换相应的页面
     * @param source 待置换页面
     * @param current 当前页面
     * @return 置换成功与否
     */
    public boolean replacePage(int source,int current){
       return replacePage(source,current,0,0);
    }

    /**
     * 供测试时使用，总是选择队首第一页置换
     * @param current 当前页面
     * @return 待置换页号
     */
    public int testReplacePage(int current){
        int result=-1;
        if(this.list.size()<length){
            replacePage(-1,current);
        }else{
            result = this.list.get(0).pageNumber;
            replacePage(result,current);
        }
        return result;
    }

    /**
     * 添加表项
     * @param pageNumber 页号
     * @param memoryNumber 内存块号
     * @param modified 修改位
     * @param address 外存地址
     */
    private void addItem(int pageNumber,int memoryNumber,int modified,long address){
        Item item = new Item(pageNumber, memoryNumber, 1, 1, modified, address);
        list.add(item);
    }

    /**
     * 展示页表的内容
     */
    public void display(){

        if(this.list.size() == 0){
            System.out.println("页表为空");
            return;
        }
        System.out.println("页号\t"+"块号");
        for (Item item : this.list) {
            System.out.println(item.getPageNumber()+"\t"+item.getMemoryNumber());
        }
    }

}
